package com.foodorder.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.foodorder.entity.Product;
import com.foodorder.entity.Store;
import com.foodorder.entity.Category;
import com.foodorder.repository.ProductRepository;
import com.foodorder.repository.StoreRepository;
import com.foodorder.repository.CategoryRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 缓存策略服务 - 多级缓存实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CacheService {
    
    private final StringRedisTemplate redisTemplate;
    private final ProductRepository productRepository;
    private final StoreRepository storeRepository;
    private final CategoryRepository categoryRepository;
    private final ObjectMapper objectMapper;
    
    // 缓存前缀
    private static final String PRODUCT_PREFIX = "cache:product:";
    private static final String STORE_PREFIX = "cache:store:";
    private static final String CATEGORY_PREFIX = "cache:category:";
    private static final String HOT_PRODUCTS_PREFIX = "cache:hot:products:";
    private static final String STORE_PRODUCTS_PREFIX = "cache:store:products:";
    private static final String CATEGORY_PRODUCTS_PREFIX = "cache:category:products:";
    
    // 缓存过期时间（秒）
    private static final int SHORT_CACHE_TTL = 300;     // 5分钟
    private static final int MEDIUM_CACHE_TTL = 1800;   // 30分钟
    private static final int LONG_CACHE_TTL = 3600;     // 1小时
    private static final int VERY_LONG_CACHE_TTL = 7200; // 2小时
    
    /**
     * 获取商品信息（带缓存）
     * 
     * @param productId 商品ID
     * @return 商品信息
     */
    public Product getProduct(Long productId) {
        String key = PRODUCT_PREFIX + productId;
        
        try {
            String cachedData = redisTemplate.opsForValue().get(key);
            if (cachedData != null) {
                return objectMapper.readValue(cachedData, Product.class);
            }
        } catch (Exception e) {
            log.warn("从缓存获取商品信息失败，ID: {}", productId, e);
        }
        
        // 缓存未命中，从数据库查询
        Product product = productRepository.findById(productId).orElse(null);
        if (product != null) {
            cacheProduct(product);
        }
        
        return product;
    }
    
    /**
     * 缓存商品信息
     * 
     * @param product 商品对象
     */
    public void cacheProduct(Product product) {
        String key = PRODUCT_PREFIX + product.getId();
        
        try {
            String jsonData = objectMapper.writeValueAsString(product);
            redisTemplate.opsForValue().set(key, jsonData, MEDIUM_CACHE_TTL, TimeUnit.SECONDS);
            log.debug("商品信息已缓存，ID: {}", product.getId());
        } catch (JsonProcessingException e) {
            log.error("缓存商品信息失败，ID: {}", product.getId(), e);
        }
    }
    
    /**
     * 获取店铺信息（带缓存）
     * 
     * @param storeId 店铺ID
     * @return 店铺信息
     */
    public Store getStore(Long storeId) {
        String key = STORE_PREFIX + storeId;
        
        try {
            String cachedData = redisTemplate.opsForValue().get(key);
            if (cachedData != null) {
                return objectMapper.readValue(cachedData, Store.class);
            }
        } catch (Exception e) {
            log.warn("从缓存获取店铺信息失败，ID: {}", storeId, e);
        }
        
        // 缓存未命中，从数据库查询
        Store store = storeRepository.findById(storeId).orElse(null);
        if (store != null) {
            cacheStore(store);
        }
        
        return store;
    }
    
    /**
     * 缓存店铺信息
     * 
     * @param store 店铺对象
     */
    public void cacheStore(Store store) {
        String key = STORE_PREFIX + store.getId();
        
        try {
            String jsonData = objectMapper.writeValueAsString(store);
            redisTemplate.opsForValue().set(key, jsonData, LONG_CACHE_TTL, TimeUnit.SECONDS);
            log.debug("店铺信息已缓存，ID: {}", store.getId());
        } catch (JsonProcessingException e) {
            log.error("缓存店铺信息失败，ID: {}", store.getId(), e);
        }
    }
    
    /**
     * 获取分类信息（带缓存）
     * 
     * @param categoryId 分类ID
     * @return 分类信息
     */
    public Category getCategory(Long categoryId) {
        String key = CATEGORY_PREFIX + categoryId;
        
        try {
            String cachedData = redisTemplate.opsForValue().get(key);
            if (cachedData != null) {
                return objectMapper.readValue(cachedData, Category.class);
            }
        } catch (Exception e) {
            log.warn("从缓存获取分类信息失败，ID: {}", categoryId, e);
        }
        
        // 缓存未命中，从数据库查询
        Category category = categoryRepository.findById(categoryId).orElse(null);
        if (category != null) {
            cacheCategory(category);
        }
        
        return category;
    }
    
    /**
     * 缓存分类信息
     * 
     * @param category 分类对象
     */
    public void cacheCategory(Category category) {
        String key = CATEGORY_PREFIX + category.getId();
        
        try {
            String jsonData = objectMapper.writeValueAsString(category);
            redisTemplate.opsForValue().set(key, jsonData, VERY_LONG_CACHE_TTL, TimeUnit.SECONDS);
            log.debug("分类信息已缓存，ID: {}", category.getId());
        } catch (JsonProcessingException e) {
            log.error("缓存分类信息失败，ID: {}", category.getId(), e);
        }
    }
    
    /**
     * 获取热门商品（带缓存）
     * 
     * @param limit 限制数量
     * @return 热门商品列表
     */
    public List<Product> getHotProducts(int limit) {
        String key = HOT_PRODUCTS_PREFIX + limit;
        
        try {
            String cachedData = redisTemplate.opsForValue().get(key);
            if (cachedData != null) {
                return objectMapper.readValue(cachedData, 
                    objectMapper.getTypeFactory().constructCollectionType(List.class, Product.class));
            }
        } catch (Exception e) {
            log.warn("从缓存获取热门商品失败", e);
        }
        
        // 缓存未命中，从数据库查询
        List<Product> hotProducts = productRepository.findPopularProducts(100, 
            org.springframework.data.domain.PageRequest.of(0, limit));
        
        if (!hotProducts.isEmpty()) {
            cacheHotProducts(hotProducts, limit);
        }
        
        return hotProducts;
    }
    
    /**
     * 缓存热门商品
     * 
     * @param products 商品列表
     * @param limit 限制数量
     */
    public void cacheHotProducts(List<Product> products, int limit) {
        String key = HOT_PRODUCTS_PREFIX + limit;
        
        try {
            String jsonData = objectMapper.writeValueAsString(products);
            redisTemplate.opsForValue().set(key, jsonData, SHORT_CACHE_TTL, TimeUnit.SECONDS);
            log.debug("热门商品列表已缓存，数量: {}", products.size());
        } catch (JsonProcessingException e) {
            log.error("缓存热门商品失败", e);
        }
    }
    
    /**
     * 获取店铺商品列表（带缓存）
     * 
     * @param storeId 店铺ID
     * @return 商品列表
     */
    public List<Product> getStoreProducts(Long storeId) {
        String key = STORE_PRODUCTS_PREFIX + storeId;
        
        try {
            String cachedData = redisTemplate.opsForValue().get(key);
            if (cachedData != null) {
                return objectMapper.readValue(cachedData, 
                    objectMapper.getTypeFactory().constructCollectionType(List.class, Product.class));
            }
        } catch (Exception e) {
            log.warn("从缓存获取店铺商品失败，店铺ID: {}", storeId, e);
        }
        
        // 缓存未命中，从数据库查询
        List<Product> products = productRepository.findByStoreIdAndStatus(storeId, Product.ProductStatus.AVAILABLE);
        
        if (!products.isEmpty()) {
            cacheStoreProducts(storeId, products);
        }
        
        return products;
    }
    
    /**
     * 缓存店铺商品列表
     * 
     * @param storeId 店铺ID
     * @param products 商品列表
     */
    public void cacheStoreProducts(Long storeId, List<Product> products) {
        String key = STORE_PRODUCTS_PREFIX + storeId;
        
        try {
            String jsonData = objectMapper.writeValueAsString(products);
            redisTemplate.opsForValue().set(key, jsonData, MEDIUM_CACHE_TTL, TimeUnit.SECONDS);
            log.debug("店铺商品列表已缓存，店铺ID: {}, 商品数量: {}", storeId, products.size());
        } catch (JsonProcessingException e) {
            log.error("缓存店铺商品失败，店铺ID: {}", storeId, e);
        }
    }
    
    /**
     * 清除商品缓存
     * 
     * @param productId 商品ID
     */
    public void evictProduct(Long productId) {
        String key = PRODUCT_PREFIX + productId;
        redisTemplate.delete(key);
        log.info("清除商品缓存，ID: {}", productId);
        
        // 同时清除相关的列表缓存
        evictRelatedCaches(productId);
    }
    
    /**
     * 清除店铺缓存
     * 
     * @param storeId 店铺ID
     */
    public void evictStore(Long storeId) {
        String key = STORE_PREFIX + storeId;
        redisTemplate.delete(key);
        
        // 清除店铺商品列表缓存
        String storeProductsKey = STORE_PRODUCTS_PREFIX + storeId;
        redisTemplate.delete(storeProductsKey);
        
        log.info("清除店铺缓存，ID: {}", storeId);
    }
    
    /**
     * 清除分类缓存
     * 
     * @param categoryId 分类ID
     */
    public void evictCategory(Long categoryId) {
        String key = CATEGORY_PREFIX + categoryId;
        redisTemplate.delete(key);
        
        // 清除分类商品列表缓存
        String categoryProductsKey = CATEGORY_PRODUCTS_PREFIX + categoryId;
        redisTemplate.delete(categoryProductsKey);
        
        log.info("清除分类缓存，ID: {}", categoryId);
    }
    
    /**
     * 清除热门商品缓存
     */
    public void evictHotProducts() {
        // 清除所有热门商品缓存
        redisTemplate.delete(redisTemplate.keys(HOT_PRODUCTS_PREFIX + "*"));
        log.info("清除热门商品缓存");
    }
    
    /**
     * 清除相关缓存
     * 
     * @param productId 商品ID
     */
    private void evictRelatedCaches(Long productId) {
        try {
            // 获取商品信息以确定需要清除的相关缓存
            Product product = productRepository.findById(productId).orElse(null);
            if (product != null) {
                // 清除店铺商品列表缓存
                String storeProductsKey = STORE_PRODUCTS_PREFIX + product.getStoreId();
                redisTemplate.delete(storeProductsKey);
                
                // 清除分类商品列表缓存
                String categoryProductsKey = CATEGORY_PRODUCTS_PREFIX + product.getCategoryId();
                redisTemplate.delete(categoryProductsKey);
                
                // 清除热门商品缓存
                evictHotProducts();
            }
        } catch (Exception e) {
            log.error("清除相关缓存失败，商品ID: {}", productId, e);
        }
    }
    
    /**
     * 预热缓存 - 在系统启动或定时任务中调用
     */
    @Async
    public void warmUpCache() {
        log.info("开始预热缓存");
        
        try {
            // 预热热门商品
            getHotProducts(20);
            
            // 预热热门店铺
            List<Store> hotStores = storeRepository.findAll(); // 这里可以优化为查找热门店铺
            for (Store store : hotStores) {
                cacheStore(store);
                getStoreProducts(store.getId());
            }
            
            // 预热所有分类
            List<Category> categories = categoryRepository.findAll();
            for (Category category : categories) {
                cacheCategory(category);
            }
            
            log.info("缓存预热完成");
        } catch (Exception e) {
            log.error("缓存预热失败", e);
        }
    }
    
    /**
     * 定时清理过期缓存
     */
    @Scheduled(fixedRate = 3600000) // 每小时执行一次
    @Async
    public void cleanExpiredCache() {
        try {
            // 这里可以实现更精细的缓存清理逻辑
            log.info("执行定时缓存清理");
            
            // 清理过期的热门商品缓存
            evictHotProducts();
            
        } catch (Exception e) {
            log.error("定时缓存清理失败", e);
        }
    }
    
    /**
     * 获取缓存统计信息
     * 
     * @return 缓存统计
     */
    public CacheStats getCacheStats() {
        try {
            long productCacheCount = redisTemplate.keys(PRODUCT_PREFIX + "*").size();
            long storeCacheCount = redisTemplate.keys(STORE_PREFIX + "*").size();
            long categoryCacheCount = redisTemplate.keys(CATEGORY_PREFIX + "*").size();
            long hotProductsCacheCount = redisTemplate.keys(HOT_PRODUCTS_PREFIX + "*").size();
            
            return new CacheStats(productCacheCount, storeCacheCount, categoryCacheCount, hotProductsCacheCount);
        } catch (Exception e) {
            log.error("获取缓存统计失败", e);
            return new CacheStats(0, 0, 0, 0);
        }
    }
    
    /**
     * 缓存统计信息类
     */
    public static class CacheStats {
        private final long productCacheCount;
        private final long storeCacheCount;
        private final long categoryCacheCount;
        private final long hotProductsCacheCount;
        
        public CacheStats(long productCacheCount, long storeCacheCount, 
                         long categoryCacheCount, long hotProductsCacheCount) {
            this.productCacheCount = productCacheCount;
            this.storeCacheCount = storeCacheCount;
            this.categoryCacheCount = categoryCacheCount;
            this.hotProductsCacheCount = hotProductsCacheCount;
        }
        
        // Getters
        public long getProductCacheCount() { return productCacheCount; }
        public long getStoreCacheCount() { return storeCacheCount; }
        public long getCategoryCacheCount() { return categoryCacheCount; }
        public long getHotProductsCacheCount() { return hotProductsCacheCount; }
        public long getTotalCacheCount() { 
            return productCacheCount + storeCacheCount + categoryCacheCount + hotProductsCacheCount; 
        }
        
        @Override
        public String toString() {
            return String.format("CacheStats{products=%d, stores=%d, categories=%d, hotProducts=%d, total=%d}",
                productCacheCount, storeCacheCount, categoryCacheCount, hotProductsCacheCount, getTotalCacheCount());
        }
    }
} 